// Create links from product pages on Best Buy site that add the products
// to your Prodect Envy wish list.
//
// version 0.95 BETA!
// 2009-02-26
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "Product Envy", and click Uninstall.
// --------------------------------------------------------------------
//
// ==UserScript==
// @name          Product Envy
// @namespace     http://prodnv.com
// @description   Add Product Envy wish list link to the Best Buy Site.
// @include       http://*.bestbuy.com/*
// @include       http://*.orkut.com/*
// ==/UserScript==

// --------------------------------------------------------------------
// This section is common code that should not need to change when
// adding support for another product site.

var prodnv_host = "http://prodnv.appspot.com/product";
var prodnv_GM_account_key = 'AB4D2DA1-0380-4843-907E-C412765FD6DD';
var prodnv_GM_account_code = 'Mashup';
var prodnv_UID_NAME = "prodNV_UID";
var prodnv_UID_VALUE_USER_WARNED = "USER_WARNED";

var prodnv_sites = new Array();

// Useful helper function for trimming whitespace at start/end of strings
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/, '');
};

function prodnv_getListLink(status, brand, model, sku, uid) {
    return prodnv_host
            + "?uid=" + uid
            + "&brand=" + brand
            + "&model=" + model
            + "&siteSku=" + sku
            + "&siteName=BestBuy"
            + "&status=" + status;
}

function prodnv_getNodes(query) {
    return document.evaluate(query, document, null,
            XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
            null);
}

function prodnv_processSite() {
    var brands = prodnv_getNodes(this.brandQuery);
    var models = prodnv_getNodes(this.modelQuery);
    var skus = prodnv_getNodes(this.skuQuery);
    var wishLists = prodnv_getNodes(this.wishListQuery);

    if (  brands && brands.snapshotLength == 1
       && models && models.snapshotLength == 1
       && skus && skus.snapshotLength == 1        
       && wishLists && wishLists.snapshotLength == 1) {

        var brand = this.getBrand(brands.snapshotItem(0));
        var model = this.getModel(models.snapshotItem(0));
        var sku = this.getSku(skus.snapshotItem(0));
        var wishListNode = wishLists.snapshotItem(0);

        this.addListLinks(brand, model, sku, wishListNode);
    }
}

function prodnv_insertAfter(new_node, existing_node) {
    // if the existing node has a following sibling, insert the current
    // node before it. otherwise appending it to the parent node
    // will correctly place it just after the existing node.

    if (existing_node.nextSibling) {
        // there is a next sibling. insert before it using the mutual
        // parent's insertBefore() method.
        existing_node.parentNode.insertBefore(new_node, existing_node.nextSibling);
    } else {
        // there is no next sibling. append to the end of the parent's
        // node list.
        existing_node.parentNode.appendChild(new_node);
    }

}

// --------------------------------------------------------------------
// Special logic for Best Buy site goes here

function prodnv_site_best_buy() {
    this.process        = prodnv_processSite;
    this.getListLink  = prodnv_getListLink;

    this.brandQuery     = "//head/title";
    this.modelQuery     = "//head/title";
    this.skuQuery       = "//div[@id='productpreview']/div[@id='imagepreview']/a/img";
    this.wishListQuery  = "//div[@class='rightcol']/div[@id='buttonblock']/a[2]";

    this.getBrand = function (node) {
        var words = new Array();
        words = node.textContent.trim().split(" ");
        var brand = words[0];
        return brand.replace(/[^A-Za-z0-9]+/g, "");
    }

    this.getModel = function (node) {
        var words = new Array();
        words = node.textContent.trim().split(" ");
        var model = words[words.length - 1];
        return model.replace(/[^A-Za-z0-9]+/g, "");
    }

    this.getSku = function (node) {
        var words = new Array();
        words = node.getAttribute("alt").trim().split(" ");
        var sku = words[0];
        return sku.replace(/[^A-Za-z0-9\/]+/g, "");
    }

    this.addListLinks = function (brand, model, sku, wishListNode) {
        var uid = GM_getValue(prodnv_UID_NAME, "");
        if (!uid || uid == "" || uid == prodnv_UID_VALUE_USER_WARNED) {
            if (!uid || uid == "") {
                alert("Product Envy integration requires that you visit and login to the Orkut site first.");
                GM_setValue(prodnv_UID_NAME, prodnv_UID_VALUE_USER_WARNED );
            }
            return;
        }

        var envyListLink = this.getListLink("envy", brand, model, sku, uid);
        var anchor = document.createElement('A');
        anchor.setAttribute("href", envyListLink);
        anchor.setAttribute("target", "_blank");

        var image = document.createElement('IMG');
        image.setAttribute("hspace", "0");
        image.setAttribute("vspace", "10");
        image.setAttribute("border", "0");
        image.setAttribute("src",
                "http://prodnv.googlecode.com/svn/trunk/greasemonkey/addToEnvyList.jpg");

        anchor.appendChild(image);
        
        wishListNode.parentNode.insertBefore(anchor, wishListNode);

        var wishListLink = this.getListLink("wish", brand, model, sku, uid);
        wishListNode.setAttribute("href", wishListLink);

// Todo: Figure out why this is not working to set our custom wish list image!!!
//      wishListNode.childNodes[0].setAttribute("src",
//                "http://prodnv.googlecode.com/svn/trunk/greasemonkey/addToWishList.jpg");
   }
}

prodnv_sites["www.bestbuy.com"] = prodnv_site_best_buy;

// --------------------------------------------------------------------
// Special logic for Orkut site goes here

function prodnv_site_orkut() {
    this.query = "//head/script";
    this.uidStart ="JSHDF['uid'] = '";

    this.process = function() {
        var scripts = prodnv_getNodes(this.query);
        if (scripts && scripts.snapshotLength > 0) {
            var content = scripts.snapshotItem(0).textContent;
            var uidStart = content.indexOf(this.uidStart) + this.uidStart.length;
            var uidEnd   = content.indexOf("'", uidStart);
            var uid = content.substring(uidStart, uidEnd);

            GM_log( prodnv_UID_NAME + " = " + uid);
            GM_setValue(prodnv_UID_NAME, uid);
        }
    }
}

prodnv_sites["www.orkut.com"] = prodnv_site_orkut;
prodnv_sites["sandbox.orkut.com"] = prodnv_site_orkut;

// --------------------------------------------------------------------
// Process site when site lookup by page host is successful ...

var siteObject = prodnv_sites[window.location.host];

if (siteObject) {
    var site = new siteObject();
    site.process();
}
